#pragma once

#include "StdAfx.h"
#include "ListenServer.h"
#include "ISocketHandler.h"

template<typename T>
class SocketManager : public ISocketListener, public Thread
{
	Concurrency::critical_section mLock;
	std::set<ISocketHandler*> mSockets;
protected:
	void onClientConnected(Socket* sock) {
		T* t = new T();
		t->clientConnected(sock);
		mLock.lock();
		mSockets.insert(t);
		mLock.unlock();
	}

public:
	SocketManager() {
	}

	bool run() {
		while(mState != Thread::ShouldQuit) {
			if(mState == Thread::ShouldPause) {
				Sleep(20);
				continue;
			}

			mLock.lock();
			std::for_each(mSockets.begin(), mSockets.end(),
				[](ISocketHandler* sock) {
					Socket* net = sock->getSocket();
					uint32 dataReady = net->getBytesAvailable();
					if(dataReady > 0) {
						std::vector<uint8> data(dataReady);
						net->receive(data);
						if(!sock->getDirectNotify())
							sock->onDataAvailable(data);
						else
							sock->notifyDataRead(data);
					}

					sock->lockWriteBuffer();
					if(sock->getWriteBufferSize() > 0) {
						std::vector<uint8> chunk(sock->getWriteBufferSize());
						sock->popWriteBuffer(chunk);
						net->send(chunk);
					}
					sock->unlockWriteBuffer();
			}
			);
			mLock.unlock();
			Sleep(10);
		}

		mLock.lock();
		std::for_each(mSockets.begin(), mSockets.end(),
				[](ISocketHandler* sock) {
					sock->getSocket()->disconnect();
		}
		);
		mLock.unlock();
		return true;
	}

	void forEach(std::function<void (T*)>& fun) {
		mLock.lock();
		for(auto itr = mSockets.begin(); itr != mSockets.end(); ++itr) {
			fun(dynamic_cast<T*>((*itr)));
		}
		mLock.unlock();
	}
};